%{
#include<stdio.h>
#include<stdlib.h>

#ifndef _DATABBASE_OPERATION_HEADER_
#define _DATABBASE_OPERATION_HEADER_

#include "../lib/header/operation.h"

#endif

extern int yylex();
extern void executeSQL();
void yyerror(char * s);



%}

%union{
    char * name;
    double d;
    int number;
    char * m_string;
    int cp;
    // 这里不能使用typedef定义的，只能采用原始的结构体定义
    struct Data * data;
}

%token <number> NUMBER
%token <m_string> CHARACTER
%token <m_string> ID
%token <data> DATA_INT DATA_DOUBLE DATA_STRING;
%token INT CHAR DOUBLE
%token CREATE EXIT INSERT SELECT DELETE UPDATE FROM DROP DATABASES DATABASE INTO VALUES WHERE AND OR TABLE SHOW DESC DELIMETER HELP NUL NOT IS EOL
%token FOREIGN PRIMARY KEY REFERENCES UNIQUE AUTOINCREMENT AS
%token <cp> CP


%start sqls

%%

// If you don't take the recursing,the statuting stack will be wrong.
// When the error occure,the statuting stack will be clear.  
// So if you don't take the 'sqls' as '%start' other while take the sql as '%start', you will find that your sqls excute rightly or wrongly one by one.
// When the first sql excutes right,the statuting tree store one: element sql, but the next right sql could not be statute rightly.Because sql can not be statute to sql.

sqls:
| sqls sql

sql: HELP DELIMETER{ executeSQL(NULL,HELPSQL);} 
| CREATE DATABASE ID DELIMETER{ executeSQL($3,CREATEDATABASESQL); }
| SHOW DATABASES DELIMETER{executeSQL(NULL,SHOWDATABASESSQL);}
| DESC ID DELIMETER { executeSQL($2,DESCSQL);} 
| EXIT DELIMETER {executeSQL(NULL,EXITSQL);}
| DROP DATABASE ID DELIMETER {executeSQL($3,DROPDATABASESQL);}
| createTableSql {printf("create sql\n");}
| selectTableSql {printf("select sql\n");}



createTableSql:
    CREATE TABLE ID'(' createFields ')' DELIMETER | 
    CREATE TABLE ID'(' createFields ',' foreignKeys')' DELIMETER 

createFields:
    createFieldWithRestrain| createFields ',' createFieldWithRestrain

createFieldWithRestrain:
    createField {printf("\nget field\n");}
    | createField PRIMARY KEY AUTOINCREMENT
    | createFieldWithRestrain NOT NUL
    | createFieldWithRestrain UNIQUE
    

createField:
    ID CHAR '(' DATA_INT ')'
   |ID INT 
   |ID DOUBLE    
    
foreignKeys:
    foreignKey| foreignKeys ',' foreignKey

foreignKey:
    FOREIGN KEY '(' ID ')' REFERENCES ID '(' ID ')'

selectTableSql:
    SELECT selectFields FROM selectTables WHERE conditions DELIMETER

selectFields:
    selectField | selectFields ',' selectField

selectField:
    ID| ID'.'ID | ID'.'ID ID| ID  ID

selectTables:
    ID | selectTables ',' ID

conditions: condition
| conditions condition

condition:
    ID CP ID 

%%

void yyerror(char * error){
    fprintf(stderr, "error: %s\n",error);
}